package com.gs.netty.support.resolver;


import com.gs.netty.core.resolver.HandlerMethodReturnValueHandler;
import com.gs.netty.websocket.remoting.req.Request;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler<Request> {

    private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();

    protected final Map<MethodParameter, HandlerMethodReturnValueHandler> argumentResolverCache =
            new ConcurrentHashMap<>(256);

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
            if (handler.supportsReturnType(returnType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, Request request) {
        HandlerMethodReturnValueHandler  handler  = getReturnValueHandler(returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
        handler.handleReturnValue(returnValue, returnType, request);
    }



    public HandlerMethodReturnValueHandlerComposite addHandlers(@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
        if (handlers != null) {
            this.returnValueHandlers.addAll(handlers);
        }
        return this;
    }

    protected HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter parameter) {
        HandlerMethodReturnValueHandler result = this.argumentResolverCache.get(parameter);

        if (result == null) {
            for (HandlerMethodReturnValueHandler returnValueHandler : this.returnValueHandlers) {
                if (returnValueHandler.supportsReturnType(parameter)) {
                    result = returnValueHandler;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }



}
